/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.rengwuxian.materialedittext;

import com.braintreepayments.cardform.ResourceTable;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentState;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.PositionLayout;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.media.image.common.AlphaType;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

/**
 * MaterialEditText class
 *
 * @author get resource class
 * @since 2021-04-14
 */
public class MaterialEditText extends PositionLayout {
    /**
     * floating_label_none
     */
    public static final int FLOATING_LABEL_NONE = 0;
    /**
     * floating_label_normal
     */
    public static final int FLOATING_LABEL_NORMAL = 1;
    /**
     * floating_label_highlight
     */
    public static final int FLOATING_LABEL_HIGHLIGHT = 2;
    private static final int DEFAUL_ICON_SIZE = 32;
    private static final int DEFAUL_BOTTOM_SPACING = 8;
    private static final int DEFAUL_TEXTSIZE = 15;
    private static final int DEFAUL_TEXTCOLOR = 0xff000000;
    private static final int DEFAUL_COLOR_DISABLED = 0xffb8babc;
    private static final int DEFAUL_PRIMARYCOLOR = 0xff0022FF;
    private static final int DEFAUL_VALUE = -1;
    private static final int ERRORCOLOR = 0xffe7492e;
    private static final int LABEL_TEXTSIZE = 12;
    private static final int WHITE_COLOR = 0x00ffffff;
    private static final int BLACK_COLOR = 0x44000000;
    private static final int DEFAUL_NUM = 3;
    private static final int DEFAUL_NUM2 = 2;
    private static final int BLACK2_COLOR = 0x1E000000;
    private static final int BLACK3_COLOR = 0xffFFA3ED;
    private static final int BLACK4_COLOR = 0xff00ffaa;
    private static final int BLACK5_COLOR = 0x8a000000;
    private static final int BLACK6_COLOR = 0x4c000000;
    private static final int BLACK7_COLOR = 0x42000000;
    private static final int DEFAUL_NUM4 = 4;
    private static final float DEFAUL_NUM3 = 160;
    private static final int MAX_NUM = 255;
    private static final int VALUE_NUM = 3;

    private int mTextSize;
    private int mCursorColor;

    /**
     * the floating label's text size.
     */
    private int floatingLabelTextSize;

    /**
     * the floating label's text color.
     */
    private int floatingLabelTextColor;

    /**
     * the bottom texts' size.
     */
    private int bottomTextSize;

    /**
     * the spacing between the main text and the floating label.
     */
    private int floatingLabelPadding;

    /**
     * the spacing between the main text and the bottom components
     */
    private int bottomSpacing;

    /**
     * whether the floating label should be shown. default is false.
     */
    private boolean floatingLabelEnabled;

    /**
     * whether to highlight the floating label's text color when focused (with the main color). default is true.
     */
    private boolean highlightFloatingLabel;

    /**
     * the base color of the line and the texts. default is black.
     */
    private int baseColor;

    /**
     * the underline's highlight color, and the highlight color of the floating
     * label if app:highlightFloatingLabel is set true in the xml. default is
     * black(when app:darkTheme is false) or white(when app:darkTheme is true)
     */
    private int primaryColor;
    private int iconColor;

    /**
     * the color for when something is wrong.(e.g. exceeding max characters)
     */
    private int errorColor;

    /**
     * min characters count limit. 0 means no limit. default is 0.
     * NOTE: the character counter will increase the View's height.
     */
    private int minCharacters;

    /**
     * max characters count limit. 0 means no limit. default is 0.
     * NOTE: the character counter will increase the View's height.
     */
    private int maxCharacters;

    /**
     * whether to show the bottom ellipsis in singleLine mode.
     * default is false. NOTE: the bottom ellipsis will increase the View's height.
     */
    private boolean singleLineEllipsis;

    /**
     * Always show the floating label, instead of animating it in/out. False by default.
     */
    private boolean floatingLabelAlwaysShown;

    /**
     * Helper text at the bottom
     */
    private String helperText;

    /**
     * Helper text color
     */
    private int helperTextColor;
    private String tempErrorText;

    /**
     * Text for the floatLabel if different from the hint
     */
    private String floatingLabelText;

    /**
     * Whether or not to show the underline. Shown by default
     */
    private boolean hideUnderline;

    /**
     * Underline's color
     */
    private int underlineColor;

    /**
     * Whether the characters count is valid
     */
    private boolean charactersCountValid;

    /**
     * Whether check the characters count at the beginning it's shown.
     */
    private boolean checkCharactersCountAtBeginning;

    /**
     * Left Icon
     */
    private PixelMap[] iconLeftBitmaps;

    private int iconSize;

    private int leftIconWidth;
    private int leftIconHeight;

    private int leftIconMarginText;
    private int leftIconMarginBottom;

    private ColorStateList textColorStateList;
    private ColorStateList textColorHintStateList;

    private Paint paint = new Paint();
    private Paint textPaint = new Paint();
    private Paint bitmapPaint = new Paint();

    private TextField textField;

    private Image leftIcon;
    private Image btTypeIcon;
    private Image underline;

    private Text helper;

    private Text floating;
    private boolean isValid;
    private String metHint;
    private OnTextListener mOnTextListener;
    private OnFocusChangedListener mFocusChangedListener;

    /**
     * MaterialEditText
     *
     * @param context
     * @param attrSet
     */
    public MaterialEditText(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(attrSet);
    }

    /**
     * MaterialEditText
     *
     * @param context
     * @param attrs
     * @param styleName
     */
    public MaterialEditText(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        init(attrs);
    }

    private void init(AttrSet attrs) {
        initComponent();
        initAttrSet(attrs);
        initComponentAction();
        refresh();
    }

    private void initComponent() {
        Component component =
                LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_materialedittext, null, false);
        addComponent(component);
        textField = (TextField) component.findComponentById(ResourceTable.Id_met_edittext);
        leftIcon = (Image) component.findComponentById(ResourceTable.Id_met_lefticon);
        btTypeIcon = (Image) component.findComponentById(ResourceTable.Id_bt_ic_type);
        underline = (Image) component.findComponentById(ResourceTable.Id_met_underline);
        helper = (Text) component.findComponentById(ResourceTable.Id_met_helper);
        floating = (Text) component.findComponentById(ResourceTable.Id_met_floating);

        paint.setAntiAlias(true);
        textPaint.setAntiAlias(true);
        bitmapPaint.setAntiAlias(true);
        iconSize = getPixel(DEFAUL_ICON_SIZE);
        bottomSpacing = dp2px(getContext(), DEFAUL_BOTTOM_SPACING);
    }

    /**
     * initAttrSet InputAttribute.PATTERN_NUMBER 3,InputAttribute.PATTERN_PASSWORD 7, InputAttribute.PATTERN_TEXT 2
     *
     * @param attrs initAttrSet
     */
    private void initAttrSet(AttrSet attrs) {
        mTextSize = AttrUtils.getDimensionFromAttr(attrs, "met_textSize", getPixel(DEFAUL_TEXTSIZE));
        String metText = AttrUtils.getStringFromAttr(attrs, "met_text", "");
        metHint = AttrUtils.getStringFromAttr(attrs, "met_hint", "  ");
        int inputType = AttrUtils.getDimensionFromAttr(attrs, "input_type", 0);
        textField.setTextInputType(inputType);
        textField.setText(metText);

        int metTextColor = AttrUtils.getColorFromAttr(attrs, "met_textColor", DEFAUL_TEXTCOLOR);
        int metTextColorDisabled = AttrUtils.getColorFromAttr(attrs, "met_textColor_disabled", DEFAUL_COLOR_DISABLED);
        textColorStateList = new ColorStateList();
        textColorStateList.addState(new int[]{ComponentState.COMPONENT_STATE_DISABLED}, metTextColorDisabled);
        textColorStateList.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, metTextColor);

        int metTextColorHint = AttrUtils.getColorFromAttr(attrs, "met_textColorHint", DEFAUL_COLOR_DISABLED);
        int metHintDisabled = AttrUtils.getColorFromAttr(attrs, "met_textColorHint_disabled", DEFAUL_COLOR_DISABLED);
        textColorHintStateList = new ColorStateList();
        textColorHintStateList.addState(
                new int[]{ComponentState.COMPONENT_STATE_DISABLED}, metHintDisabled);
        textColorHintStateList.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, metTextColorHint);
        baseColor = AttrUtils.getColorFromAttr(attrs, "met_baseColor", Color.BLACK.getValue());
        primaryColor = AttrUtils.getColorFromAttr(attrs, "met_primaryColor", DEFAUL_PRIMARYCOLOR);
        iconColor = AttrUtils.getColorFromAttr(attrs, "met_iconColor", DEFAUL_PRIMARYCOLOR);
        mCursorColor = AttrUtils.getColorFromAttr(attrs, "met_cursorColor", DEFAUL_PRIMARYCOLOR);
        setCursorColor(mCursorColor);

        String mode = AttrUtils.getStringFromAttr(attrs, "met_floatingLabel", null);
        if ("normal".equals(mode)) {
            setFloatingLabelInternal(FLOATING_LABEL_NORMAL);
        } else if ("highlight".equals(mode)) {
            setFloatingLabelInternal(FLOATING_LABEL_HIGHLIGHT);
        } else {
            setFloatingLabelInternal(FLOATING_LABEL_NONE);
        }
        errorColor = AttrUtils.getColorFromAttr(attrs, "met_errorColor", ERRORCOLOR);
        minCharacters = AttrUtils.getIntFromAttr(attrs, "met_minCharacters", 0);
        maxCharacters = AttrUtils.getIntFromAttr(attrs, "met_maxCharacters", 0);
        singleLineEllipsis = AttrUtils.getBooleanFromAttr(attrs, "met_singleLineEllipsis", false);
        helperText = AttrUtils.getStringFromAttr(attrs, "met_helperText", "");
        helperTextColor = AttrUtils.getColorFromAttr(attrs, "met_helperTextColor", 0);
        bottomSpacing = AttrUtils.getDimensionFromAttr(attrs, "met_bottomSpacing", getPixel(DEFAUL_BOTTOM_SPACING));
        floatingLabelText = AttrUtils.getStringFromAttr(attrs, "met_floatingLabelText", metHint);
        floatingLabelPadding = AttrUtils.getDimensionFromAttr(attrs, "met_floatingLabelPadding", bottomSpacing);
        floatingLabelTextSize =
                AttrUtils.getDimensionFromAttr(attrs, "met_floatingLabelTextSize", dp2px(getContext(), LABEL_TEXTSIZE));
        floatingLabelTextColor = AttrUtils.getColorFromAttr(attrs, "met_floatingLabelTextColor", DEFAUL_VALUE);
        bottomTextSize = AttrUtils.getDimensionFromAttr(
                attrs, "met_bottomTextSize", dp2px(getContext(), LABEL_TEXTSIZE));
        hideUnderline = AttrUtils.getBooleanFromAttr(attrs, "met_hideUnderline", false);
        underlineColor = AttrUtils.getColorFromAttr(attrs, "met_underlineColor", DEFAUL_VALUE);
        initLayoutConfig(metText, attrs);
    }

    private void initLayoutConfig(String metText, AttrSet attrs) {
        leftIconWidth = AttrUtils.getDimensionFromAttr(attrs, "met_iconLeftWidth", iconSize);
        leftIconHeight = AttrUtils.getDimensionFromAttr(attrs, "met_iconLeftHeight", iconSize);
        leftIconMarginText = AttrUtils.getDimensionFromAttr(attrs, "met_iconLeftMarginText", getPixel(LABEL_TEXTSIZE));
        leftIconMarginBottom = AttrUtils.getDimensionFromAttr(attrs, "met_iconLeftMarginBottom", 0);
        Element leftElement = AttrUtils.getElementFromAttr(attrs, "met_iconLeft", null);
        if (leftElement != null) {
            iconLeftBitmaps = generateIconBitmaps(leftElement, leftIconWidth, leftIconHeight);
        }
        floatingLabelAlwaysShown = AttrUtils.getBooleanFromAttr(attrs, "met_floatingLabelAlwaysShown", false);
        checkCharactersCountAtBeginning =
                AttrUtils.getBooleanFromAttr(attrs, "met_checkCharactersCountAtBeginning", true);
        textField.setHint(metHint);
        if (!checkCharactersCountAtBeginning) {
            charactersCountValid = true;
        } else {
            charactersCountValid = true;
            if (minCharacters > 0) {
                if (metText.length() < minCharacters) {
                    charactersCountValid = false;
                }
            }
            if (maxCharacters > 0) {
                if (metText.length() > maxCharacters) {
                    charactersCountValid = false;
                }
            }
        }
        if (iconLeftBitmaps != null) {
            LayoutConfig layoutConfig = leftIcon.getLayoutConfig();
            layoutConfig.width = iconLeftBitmaps[0].getImageInfo().size.width;
            layoutConfig.setMarginRight(leftIconMarginText);
            leftIcon.setLayoutConfig(layoutConfig);
        }
        if (bottomSpacing != 0) {
            LayoutConfig layoutConfig = underline.getLayoutConfig();
            layoutConfig.setMarginTop(bottomSpacing);
            underline.setLayoutConfig(layoutConfig);
        }
        if (floatingLabelPadding != 0) {
            LayoutConfig layoutConfig = floating.getLayoutConfig();
            layoutConfig.setMarginBottom(floatingLabelPadding);
            floating.setLayoutConfig(layoutConfig);
        }
    }

    private void initComponentAction() {
        textField.setComponentStateChangedListener(
                new ComponentStateChangedListener() {
                    @Override
                    public void onComponentStateChanged(Component component, int i) {
                        refresh();
                    }
                });
        textField.setFocusChangedListener(
                new FocusChangedListener() {
                    @Override
                    public void onFocusChange(Component component, boolean isFocus) {
                        refresh();
                        if (mFocusChangedListener != null) {
                            mFocusChangedListener.onFocusChanged(isFocus);
                        }
                    }
                });
        textField.addTextObserver(
                new Text.TextObserver() {
                    @Override
                    public void onTextUpdated(String s, int start, int before, int count) {
                        if (mOnTextListener != null) {
                            mOnTextListener.onTextChanged(s);
                        }
                        tempErrorText = "";
                        if (minCharacters > 0) {
                            if (s.length() < minCharacters) {
                                charactersCountValid = false;
                                refresh();
                                return;
                            }
                        }

                        if (maxCharacters > 0) {
                            if (s.length() > maxCharacters) {
                                charactersCountValid = false;
                                refresh();
                                return;
                            }
                        }

                        charactersCountValid = true;
                        refresh();
                    }
                });
        underlineDrawTask();
        leftIconDrawTask();
    }

    private void underlineDrawTask() {
        underline.addDrawTask(
                new DrawTask() {
                    @Override
                    public void onDraw(Component component, Canvas canvas) {
                        if (!hideUnderline) {
                            int lineStartY = 0;
                            int startX = 0;
                            int endX = underline.getWidth();
                            if (!isInternalValid()) {
                                // not valid
                                paint.setColor(new Color(errorColor));
                                int tempStartY = lineStartY + getPixel(FLOATING_LABEL_HIGHLIGHT);
                                canvas.drawRect(
                                        new RectFloat(startX, lineStartY, endX, tempStartY), paint);
                            } else if (!textField.isEnabled()) { // disabled
                                paint.setColor(
                                        new Color(
                                                underlineColor != DEFAUL_VALUE
                                                        ? underlineColor
                                                        : baseColor & WHITE_COLOR | BLACK_COLOR));
                                int interval = getPixel(1);
                                for (int xoffset = 0; xoffset < getWidth(); xoffset += interval * DEFAUL_NUM) {
                                    canvas.drawRect(
                                            new RectFloat(
                                                    startX + xoffset,
                                                    lineStartY,
                                                    startX + xoffset + interval,
                                                    lineStartY + getPixel(1)),
                                            paint);
                                }
                            } else if (textField.hasFocus()) { // focused
                                paint.setColor(new Color(primaryColor));
                                int temp = lineStartY + getPixel(DEFAUL_NUM2);
                                canvas.drawRect(
                                        new RectFloat(startX, lineStartY, endX, temp), paint);
                            } else { // normal
                                paint.setColor(
                                        new Color(
                                                underlineColor != DEFAUL_VALUE
                                                        ? underlineColor
                                                        : baseColor & WHITE_COLOR | BLACK2_COLOR));
                                canvas.drawRect(
                                        new RectFloat(startX, lineStartY, endX, lineStartY + getPixel(1)), paint);
                            }
                        }
                    }
                });
    }

    private void leftIconDrawTask() {
        leftIcon.addDrawTask(
                new DrawTask() {
                    @Override
                    public void onDraw(Component component, Canvas canvas) {
                        if (iconLeftBitmaps != null) {
                            PixelMap pixelMap =
                                    iconLeftBitmaps[
                                            !isInternalValid()
                                                    ? DEFAUL_NUM
                                                    : !textField.isEnabled() ? DEFAUL_NUM2
                                                    : textField.hasFocus() ? 1 : 0];
                            int top =
                                    textField.getHeight()
                                            + floating.getHeight()
                                            - pixelMap.getImageInfo().size.height
                                            - leftIconMarginBottom
                                            + floatingLabelPadding;
                            if (top < 0) {
                                top = 0;
                            }
                            canvas.drawPixelMapHolder(new PixelMapHolder(pixelMap), 0, top, bitmapPaint);
                        }
                    }
                });
    }

    public TextField getTextField() {
        return textField;
    }

    public Image getTypeIcon() {
        return btTypeIcon;
    }

    /**
     * setErrorText
     *
     * @param errorText
     */
    public void setErrorText(String errorText) {
        tempErrorText = errorText;
        refreshError();
    }

    /**
     * setHintText
     *
     * @param hintText
     */
    public void setHintText(String hintText) {
        metHint = hintText;
        textField.setHint(metHint);
    }

    public void setValid(boolean valid) {
        isValid = valid;
    }

    public boolean getValid() {
        return isValid;
    }

    private void refreshTextField() {
        textField.setTextSize(mTextSize);
        if (singleLineEllipsis) {
            textField.setMultipleLine(false);
            textField.setMaxTextLines(1);
        } else {
            textField.setMultipleLine(true);
            textField.setMaxTextLines(MAX_NUM);
        }
        if (textField.isEnabled()) {
            textField.setTextColor(
                    new Color(
                            textColorStateList.getColorForState(
                                    new int[]{ComponentState.COMPONENT_STATE_EMPTY}, BLACK3_COLOR)));
            textField.setHintColor(
                    new Color(
                            textColorHintStateList.getColorForState(
                                    new int[]{ComponentState.COMPONENT_STATE_EMPTY}, BLACK4_COLOR)));
        } else {
            textField.setTextColor(
                    new Color(
                            textColorStateList.getColorForState(
                                    new int[]{ComponentState.COMPONENT_STATE_DISABLED}, DEFAUL_COLOR_DISABLED)));
            textField.setHintColor(
                    new Color(
                            textColorHintStateList.getColorForState(
                                    new int[]{ComponentState.COMPONENT_STATE_DISABLED}, DEFAUL_COLOR_DISABLED)));
        }
        if (textField.isFocused()) {
            textField.setHint("");
        } else {
            textField.setHint(metHint);
        }
    }

    private void refreshIcon() {
        if (iconLeftBitmaps != null) {
            leftIcon.setVisibility(Component.VISIBLE);
            leftIcon.invalidate();
        } else {
            leftIcon.setVisibility(Component.HIDE);
        }
    }

    private void refreshError() {
        if (tempErrorText != null && tempErrorText.length() > 0 && !isValid) {
            helper.setText(tempErrorText);
            helper.setTextSize(bottomTextSize);
            helper.setTextColor(new Color(errorColor));
        } else if (textField.hasFocus() && helperText != null && helperText.length() > 0) {
            helper.setText(helperText);
            helper.setTextSize(bottomTextSize);
            helper.setTextColor(new Color(helperTextColor));
        } else {
            helper.setText(" ");
        }
    }

    private void refreshFloat() {
        if (floatingLabelEnabled && floatingLabelText != null && floatingLabelText.length() > 0) {
            floating.setVisibility(Component.VISIBLE);
            floating.setTextSize(floatingLabelTextSize);
            if (floatingLabelAlwaysShown || (textField.getText() != null && textField.getText().length() > 0)) {
                floating.setText(floatingLabelText);
            } else {
                floating.setText(" ");
            }
            if (highlightFloatingLabel && textField.hasFocus()) {
                floating.setTextColor(new Color(primaryColor));
                floating.setText(floatingLabelText);
            } else {
                floating.setTextColor(
                        new Color(
                                floatingLabelTextColor != DEFAUL_VALUE
                                        ? floatingLabelTextColor
                                        : (baseColor & WHITE_COLOR | BLACK_COLOR)));
            }
        } else {
            floating.setVisibility(Component.INVISIBLE);
        }
    }

    private void refresh() {
        refreshTextField();
        refreshError();
        refreshFloat();
        underline.invalidate();
    }

    private int getPixel(int dp) {
        return dp2px(getContext(), dp);
    }

    private void setFloatingLabelInternal(int mode) {
        switch (mode) {
            case FLOATING_LABEL_NORMAL:
                floatingLabelEnabled = true;
                highlightFloatingLabel = false;
                break;
            case FLOATING_LABEL_HIGHLIGHT:
                floatingLabelEnabled = true;
                highlightFloatingLabel = true;
                break;
            default:
                floatingLabelEnabled = false;
                highlightFloatingLabel = false;
                break;
        }
    }

    private PixelMap[] generateIconBitmaps(Element drawable, int width, int height) {
        PixelMap bitmap = drawableToPixelmap(drawable);
        Canvas canvas = new Canvas(new Texture(bitmap));
        drawable.setBounds(0, 0, bitmap.getImageInfo().size.width, bitmap.getImageInfo().size.height);
        drawable.drawToCanvas(canvas);
        return generateBitmaps(copy(bitmap, width, height));
    }

    private PixelMap drawableToPixelmap(Element drawable) {
        if (drawable instanceof Element) {
            return ((PixelMapElement) drawable).getPixelMap();
        }
        return ((PixelMapElement) drawable).getPixelMap();
    }

    private PixelMap copy(PixelMap source, int width, int height) {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.alphaType = AlphaType.PREMUL;
        initializationOptions.size = new Size(width, height);
        return PixelMap.create(source, initializationOptions);
    }

    private PixelMap[] generateBitmaps(PixelMap originPixelMap) {
        PixelMap[] iconBitmaps = new PixelMap[DEFAUL_NUM4];
        PixelMap origin = scaleIcon(originPixelMap);
        iconBitmaps[0] = copy(origin, origin.getImageInfo().size.width, origin.getImageInfo().size.height);
        Canvas canvas = new Canvas(new Texture(iconBitmaps[0]));
        canvas.drawColor(
                baseColor & WHITE_COLOR | (Colors.isLight(baseColor) ? DEFAUL_TEXTCOLOR : BLACK5_COLOR),
                Canvas.PorterDuffMode.SRC_IN);
        iconBitmaps[1] = copy(origin, origin.getImageInfo().size.width, origin.getImageInfo().size.height);
        canvas = new Canvas(new Texture(iconBitmaps[1]));
        canvas.drawColor(iconColor, Canvas.PorterDuffMode.SRC_IN);
        iconBitmaps[DEFAUL_NUM2] = copy(origin, origin.getImageInfo().size.width, origin.getImageInfo().size.height);
        canvas = new Canvas(new Texture(iconBitmaps[DEFAUL_NUM2]));
        canvas.drawColor(
                baseColor & WHITE_COLOR | (Colors.isLight(baseColor) ? BLACK6_COLOR : BLACK7_COLOR),
                Canvas.PorterDuffMode.SRC_IN);
        iconBitmaps[VALUE_NUM] = copy(origin, origin.getImageInfo().size.width, origin.getImageInfo().size.height);
        canvas = new Canvas(new Texture(iconBitmaps[VALUE_NUM]));
        canvas.drawColor(errorColor, Canvas.PorterDuffMode.SRC_IN);
        return iconBitmaps;
    }

    private PixelMap scaleIcon(PixelMap origin) {
        int width = origin.getImageInfo().size.width;
        int height = origin.getImageInfo().size.height;
        int size = Math.max(width, height);
        if (size == iconSize) {
            return origin;
        } else if (size > iconSize) {
            int scaledWidth;
            int scaledHeight;
            if (width > iconSize) {
                scaledWidth = iconSize;
                scaledHeight = (int) (iconSize * ((float) height / width));
            } else {
                scaledHeight = iconSize;
                scaledWidth = (int) (iconSize * ((float) width / height));
            }
            return copy(origin, scaledWidth, scaledHeight);
        } else {
            return origin;
        }
    }

    /**
     * setCursorColor
     *
     * @param color
     */
    public void setCursorColor(int color) {
        if (color == 0) {
            return;
        }
        mCursorColor = color;
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(RgbColor.fromArgbInt(mCursorColor));
        textField.setCursorElement(shapeElement);
    }

    /**
     * textField setText
     *
     * @param text
     */
    public void setText(String text) {
        if (text == null) {
            return;
        }
        textField.setText(text);
    }

    /**
     * gettext
     *
     * @return string
     */
    public String getText() {
        return textField.getText();
    }

    /**
     * set textField Enabled
     *
     * @param enable
     */
    public void setEnabled(boolean enable) {
        textField.setEnabled(enable);
    }

    public boolean isEnabled() {
        return textField.isEnabled();
    }

    private boolean isInternalValid() {
        return (tempErrorText == null || tempErrorText.length() == 0) && isCharactersCountValid();
    }

    public boolean isCharactersCountValid() {
        return charactersCountValid;
    }

    private int dp2px(Context context, float dp) {
        return (int) (context.getResourceManager().getDeviceCapability().screenDensity / DEFAUL_NUM3 * dp);
    }

    public void setOnTextListener(OnTextListener listener) {
        mOnTextListener = listener;
    }

    public void setFocusChangedListener(OnFocusChangedListener listener) {
        mFocusChangedListener = listener;
    }

    /**
     * OnTextListener
     *
     * @author OnTextListener
     * @since 2021-04-14
     */
    public interface OnTextListener {
        /**
         * onTextChanged
         *
         * @param text
         */
        void onTextChanged(String text);
    }

    /**
     * OnFocusChangedListener
     *
     * @author OnFocusChangedListener
     * @since 2021-04-14
     */
    public interface OnFocusChangedListener {
        /**
         * onFocusChanged
         *
         * @param isFocus
         */
        void onFocusChanged(boolean isFocus);
    }
}
